<?php

namespace App\Abstracts\Providers;

use App\Abstracts\Models\AbstractModelRoleAccessRelation;
use Hilaoyu\Utils\UtilSupport;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Hilaoyu\LaravelExtend\Model;


abstract class AbstractGateDefineServiceProvider extends ServiceProvider
{

    public function boot()
    {


    }

    public function register(){
        $actions = array_keys(AbstractModelRoleAccessRelation::getActionName());
        array_push($actions,'view','edit','delete');

        foreach ($actions as $action){
            if(Str::startsWith($action,'allow_')){
                $action = Str::substr($action,Str::length('allow_'));
            }
            Gate::define($action,function ($user,$identifier='') use ($action){
                try{
                    //dd($user,$identifier);
                    //comResponse()->withDebug([$user,$identifier],'Gate_define');

                    $model = $this->checkIdentifierAndModel($identifier);

                    return $this->checkAccess($user,$identifier,$action,$model);
                }catch (\Exception $e){

                    comResponse()->withDebug([
                        'exception' => $e->getMessage(),
                        'user'=>$user,
                        'action'=>$action,
                        'identifier' => $identifier,
                    ],'gate_check');
                    return false;
                }
                return false;
            });
        }

    }

    protected function checkIdentifierAndModel(&$identifier){
        $model = null;
        if ($identifier instanceof Model) {
            $model = $identifier;
        } elseif (is_subclass_of($identifier, Model::class)) {
            $model = UtilSupport::makeClassSingle($identifier);
        }

        if($model){
            $identifier = UtilSupport::tryQuiet(function ()use ($model){
                return $model->accessGetAccessIdentifier();
            });
        }

        $identifier = trim((string)$identifier);

        return $model;
    }


    protected function checkAccess($user,$identifier,$action,$model=null){

        $identifier = trim($identifier);
        if(empty($identifier)){
            return true;
        }

        $access = $this->getUserAccesses($user,$identifier);

        //dump($access,$action);
        if (is_bool($access)) {
            return $access;
        }

        $user_auth_id = UtilSupport::tryQuiet(function ()use ($user){
           return $user->getAuthIdentifier() ;
        });


        $model_with_owner = false;
        $model_owner_id = false;


        if ($model
            && UtilSupport::tryQuiet(function () use($model){
                return $model->accessGetOwnerFieldName();
            })
        ) {
            $model_with_owner = true;
            $model_owner_id = $model->accessGetOwnerId();
        }



        @list($action, $scope) = explode('_', $action);


        if ($action == 'create') {
            return data_get($access, 'allow_' . $action, false);
        }


        if (!empty($scope)) {
            $check = data_get($access, 'allow_' . $action . '_' . $scope, false);


            if (!$check) {
                return false;
            }

            if ($scope == 'all') {
                return true;
            } elseif ($scope == 'group') {
                //dd($check);
                if (!$model || !$model_with_owner) {
                    return true;
                }

                if ($model_owner_id == $user_auth_id) {
                    return true;
                }

                return (bool)UtilSupport::tryQuiet(function ()use($user,$model_owner_id){
                    $user->getSameRoleModels()->firstWhere('id', '=', $model_owner_id);
                });
            } elseif ($scope == 'own') {

                if (!$model || !$model_with_owner) {
                    return true;
                }

                return $model_owner_id == $user_auth_id;
            }

            return false;
        }


        foreach (['all', 'group', 'own'] as $scope) {
            if ($this->checkAccess($user,$identifier,$action . '_' . $scope,$model)) {
                return $scope;
            }
        }

        return false;
    }

    abstract  protected function getUserAccesses($user,$identifier) ;
}
